﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Consul;

namespace Infrastructure.Centers
{
    /// <summary>
    /// 服务中心客户端：根据服务名称获取可用服务实例地址（支持静态配置与动态Consul发现）
    /// 体现了服务发现的核心职责，通过组合静态配置与动态发现机制，为微服务架构提供了灵活的服务定位能力。
    /// </summary>
    public class ServiceCenter : IServiceCenter
    {
        private readonly IConsulClient _consulClient;        // Consul客户端实例
        private readonly ServiceCenterOption _serviceConfig; // 服务中心配置

        /// <summary>
        /// 构造函数（依赖注入）
        /// </summary>
        /// <param name="consulClient">Consul客户端</param>
        /// <param name="serviceConfig">服务中心配置</param>
        public ServiceCenter(
            IConsulClient consulClient,
            ServiceCenterOption serviceConfig)
        {
            _consulClient = consulClient;
            _serviceConfig = serviceConfig;
        }

        /// <summary>
        /// 获取指定服务的可用实例
        /// </summary>
        /// <param name="name">服务注册名称</param>
        /// <returns>服务客户端实例</returns>
        /// <exception cref="Exception">服务不存在时抛出异常</exception>
        public Service Service(string name)
        {
            // 参数校验
            if (string.IsNullOrEmpty(name))
                throw new Exception("服务名字不可为空");

            // 优先检查静态配置服务
            if (IsPreconfiguredService(name, out var staticAddress))
                return new Service(name, staticAddress);

            // 从Consul动态查询服务实例
            var instances = GetConsulServiceInstances(name).GetAwaiter().GetResult();
            if (instances?.Length > 0)
            {
                // 随机选择一个实例（简单负载均衡）
                var selectedInstance = SelectRandomInstance(instances);
                return BuildServiceClient(name, selectedInstance);
            }

            // 无可用服务时抛出异常
            throw new Exception($"[{name}]无可用服务");
        }

        #region 私有方法
        //--------------------------------------------------

        /// <summary>
        /// 检查是否为预配置的静态服务
        /// </summary>
        private bool IsPreconfiguredService(string name, out string address)
        {
            address = null;
            return _serviceConfig?.ConstService != null
                && _serviceConfig.ConstService.TryGetValue(name, out address);
        }

        /// <summary>
        /// 从Consul查询健康服务实例
        /// </summary>
        private async Task<CatalogService[]> GetConsulServiceInstances(string serviceName)
        {
            var queryResult = await _consulClient.Catalog.Service(serviceName);
            return queryResult?.Response;
        }

        /// <summary>
        /// 随机选择服务实例（简单负载均衡策略）
        /// </summary>
        private CatalogService SelectRandomInstance(CatalogService[] instances)
        {
            return instances[new Random().Next(0, instances.Length)];
        }

        /// <summary>
        /// 构建服务客户端连接信息
        /// </summary>
        private Service BuildServiceClient(string name, CatalogService instance)
        {
            var endpoint = $"{instance.ServiceAddress}:{instance.ServicePort}";
            return new Service(name, endpoint);
        }

        #endregion
    }
}
